package stream;

import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2024/09/11
 */
public class StreamTest2 {

    List<Person> personList = new ArrayList<Person>();
    List<Integer> simpleList = Arrays.asList(15, 22, 9, 11, 33, 52, 14);

    @Before
    public void initData() {
        personList.add(new Person("张三", 3000, 23, "男", "太原"));
        personList.add(new Person("李四", 7000, 34, "男", "西安"));
        personList.add(new Person("王五", 5200, 22, "女", "太原"));
        personList.add(new Person("小黑", 1500, 33, "女", "上海"));
        personList.add(new Person("狗子", 8000, 44, "女", "北京"));
        personList.add(new Person("铁蛋", 6200, 36, "女", "南京"));
    }

    @Test
    public void foreachTest() {
        //forEach：遍历，传输进去一个消费者，将这个流消费掉
        personList.stream().forEach(System.out::println);
    }

    @Test
    public void findTest() {
        //findAny：随便拿一个数据，在单线程中不显现出效果，在多线程中出现效果，每个线程都会拿一个结果
        Optional<Integer> any = simpleList.stream().findAny();
        //如果有数据就将它消费掉
        any.ifPresent(System.out::println);
        //findFirst：拿到都一个元素
        Optional<Integer> first = simpleList.stream().findFirst();
        //如果有数据就将它消费掉
        first.ifPresent(System.out::println);

        System.out.println("----------------------------------");

        //parallelStream:直接变成多线程方式
        Optional<Integer> anyMore = simpleList.parallelStream().findAny();
        anyMore.ifPresent(System.out::println);
        Optional<Integer> firstMore = simpleList.parallelStream().findFirst();
        firstMore.ifPresent(System.out::println);
    }

    @Test

    public void matchTest() {//mach:匹配
        //mach:匹配
        // allMatch:所有的数据必须满足这个条件,否则输出float，传进去的叫断言
        boolean b = personList.stream().allMatch(person -> person.getSalary() > 3000);
        System.out.println(b);

        //anyMatch:随便一个数值满足条件，输出true
        b = personList.stream().anyMatch(person -> person.getSalary() > 3000);
        System.out.println(b);
    }

    @Test
    public void countTest() {
        long count = personList.stream().count();
        System.out.println(count);
        //平均数
        OptionalDouble average = simpleList.stream().mapToInt(i -> i).average();
        average.ifPresent(System.out::println);

        //求最大值
        OptionalInt max = new Random().ints(5).max();
        max.ifPresent(System.out::println);

        //求最小值
        OptionalInt min = new Random().ints(5).min();
        min.ifPresent(System.out::println);

        //求工资最高的员工
        Optional<Person> max1 = personList.stream().max(Comparator.comparingInt(Person::getSalary));
        max1.ifPresent(System.out::println);
    }

    @Test
    public void reduceTest() {//归约(reduce)
        //identity:代表n1一开始是几
        int reduce = IntStream.of(2, 1, 3, 4).reduce(1, (n1, n2) -> n1 * n2);//累乘
        int reduce1 = IntStream.of(2, 1, 3, 4).reduce(0, (n1, n2) -> n1 + n2);//累加
        System.out.println(reduce);
        System.out.println(reduce1);
    }

    @Test
    public void joiningTest() {//接合(joining)
        List<String> list = Arrays.asList("A", "B", "C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串：" + string);
    }

    @Test
    public void partitioningByTest() {//分组(partitioningBy/groupingBy)
        //按工资分区
        Map<Boolean, List<Person>> collect = personList.stream().collect(Collectors.partitioningBy(person -> person.getSalary() > 5000));
        System.out.println(collect);
        //按性别分组
        Map<String, List<Person>> collect1 = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        System.out.println(collect1);
        System.out.println(collect1.get("男"));
    }

    @Test
    public void collectTest() {//归集(toList/toSet/toMap)
        List<Integer> toList = simpleList.stream().collect(Collectors.toList());
        Set<Integer> toSet = simpleList.stream().collect(Collectors.toSet());
        //要处理 key和value
        Map<String, Person> collect = personList.stream().collect(Collectors.toMap(person -> person.getName(), person -> person));
        System.out.println(collect);
    }


    //-------Stream中间操作----------------------------
    @Test
    public void filterTest() {//筛选（filter）
        personList.stream().filter(person -> person.getSalary() > 5000)
                .forEach(System.out::println);//必须要有终止操作，整个stream才能运行
    }

    @Test
    public void mapTest() {//映射(map/flatMap)
        //拿到每个员工的工资
        List<Integer> collect = personList.stream().map(Person::getSalary).collect(Collectors.toList());
        System.out.println(collect);

//        personList.stream().map(person -> person.setSalary(person.getSalary()+1000))  报错的原因：操作是改变数值，是需要返回值，这样写没有返回值，要return
        personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 1000);
            return person;
        }).forEach(System.out::println);
    }

    @Test
    public void sortedTest() {//排序(sorted)
        personList.stream().sorted(Comparator.comparingInt(Person::getSalary)).forEach(System.out::println);
        //原始比较器
        personList.stream().sorted((p1, p2) -> p1.getSalary() - p2.getSalary()).forEach(System.out::println);
    }

    @Test
    public void peekTest() {//peek操作
        // 在stream中间进行调试，因为stream不支持debug，peek的作用：1.在数据处理的中途执行某个操作，比如看看到了这一段代码是什么样的数据
        List<Person> collect = personList.stream().filter(p -> p.getSalary() > 5000)
                .peek(System.out::println).collect(Collectors.toList());
        // 作用2.修改元素的信息，给每个员工涨工资一千，
        personList.stream().peek(p -> p.setSalary(p.getSalary() + 1000))
                .forEach(System.out::println);
    }

    @Test
    public void otherTest() {
        // distinct():去掉重复数据
        // skip():跳过几个数据
        // limit():限制使用几个数据


        //拿到工资最高的三个员工
        personList.stream().sorted((p1, p2) -> p2.getSalary() - p1.getSalary()).limit(3).forEach(System.out::println);


        IntStream.of(1,3,3,3,3,5,5,5,66,4,54,5,5,5,5).distinct().skip(1).forEach(System.out::println);
    }


    @Test
    public void Test(){//找出男员工和女员工里工资最高的人

        //第一种写法
        Stream<Person> mam = personList.stream().filter(person -> person.getSex() == "男").sorted((p1, p2) -> p2.getSalary() - p1.getSalary()).limit(1);
        Stream<Person> nv = personList.stream().filter(person -> person.getSex() == "女").sorted((p1, p2) -> p2.getSalary() - p1.getSalary()).limit(1);
        mam.forEach(System.out::println);
        nv.forEach(System.out::println);


        System.out.println("第二种写法");
        //第二种写法
        Map<String, List<Person>> collect = personList.stream().collect(Collectors.groupingBy(person -> person.getSex()));
        collect.get("男").stream().sorted((p1, p2) -> p2.getSalary() - p1.getSalary()).limit(1).forEach(System.out::println);
        collect.get("女").stream().sorted((p1, p2) -> p2.getSalary() - p1.getSalary()).limit(1).forEach(System.out::println);
    }
}



